/*
 * Licensed Materials - Property of tenxcloud.com
 * (C) Copyright 2018 TenxCloud. All Rights Reserved.
 * 2018-06-13  @author lizhen
 */

package middleware

import (
	"github.com/gin-gonic/gin"
	"github.com/golang/glog"
	"github.com/jinzhu/gorm"
	"modules.tenxcloud.com/common/composite"
	"modules.tenxcloud.com/common/model/user"
	"modules.tenxcloud.com/common/utility/errors"
)

const (
	LoginUserKey = "login-user"
)

func Authorization(c *gin.Context) {
	rawToken := c.Request.Header.Get("Authorization")
	if rawToken == "" {
		glog.Warning("unauthorized access, token not specified")
		c.AbortWithStatusJSON(errors.Unauthorized("token should be specified in header with 'Authorization' key"))
		return
	}
	var username, token string
	ok, bearerToken := composite.JWTAuthorizer.IsBearerToken(rawToken)
	if ok {
		loginInfo, err := composite.OIDCAuthorizer.Validate(bearerToken)
		if err != nil {
			c.AbortWithStatusJSON(errors.Unauthorized(err.Error()))
			return
		}
		username = loginInfo.GetUserName()
		//token = loginInfo.GetUserToken()
	} else {
		username = c.Request.Header.Get("username")
		if username == "" {
			glog.Warning("unauthorized access, username not specified")
			c.AbortWithStatusJSON(errors.Unauthorized("username should be specified in header"))
			return
		}
		if len(rawToken) <= tokenPrefixLength {
			glog.Warning("unauthorized access, invalid token format")
			c.AbortWithStatusJSON(errors.Unauthorized("invalid token format"))
			return
		}
		token = rawToken[tokenPrefixLength:]
	}
	db, err := composite.Database.GetOrm()
	if err != nil {
		glog.Errorf("get db connection for getting user failed, %s", err)
		c.AbortWithStatusJSON(errors.InternalServerError(err))
		return
	}
	u, err := user.FindOneByName(username, db)
	if err != nil {
		if gorm.IsRecordNotFoundError(err) {
			glog.Errorf("unauthorized access, user not found, %s", username)
			c.AbortWithStatusJSON(errors.Unauthorized("user not found"))
			return
		}
		glog.Errorf("get user from db failed, user %s, %s", username, err)
		c.AbortWithStatusJSON(errors.InternalServerError(err))
		return
	}
	if token != "" && token != u.Token {
		glog.Warningf("unauthorized access, token mismatch, user %s", username)
		c.AbortWithStatusJSON(errors.Unauthorized("token mismatch"))
		return
	}
	c.Set(LoginUserKey, u)
	c.Next()
}

const tokenPrefixLength = len("token ")
